{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 实测技术分析"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 本段代码利用quantOS系统分析了几个常见技术信号有效性，我们选取了两个技术形态：三根阳\n",
    "线，金叉死叉，以及一个技术指标：跳空高开。大致步骤如下：\n",
    "\n",
    "\n",
    "1.首先通过`add_formula`功能将信号用公式表达并计算，再加入到`DataView`中\n",
    "\n",
    "2.利用信号测试模块`jaqs.research.SignalDigger`分析信号有效性"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "## 1. 准备工作"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.1 设置参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import unicode_literals\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline  \n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "\n",
    "import seaborn as sns\n",
    "\n",
    "from jaqs.data import DataView\n",
    "from jaqs.data import RemoteDataService\n",
    "from jaqs.research import SignalDigger\n",
    "import jaqs.util as jutil"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 设置服务器地址、用户名密码\n",
    "\n",
    "# 如果没有使用quantos金融终端，请自行替换phone,token内容\n",
    "import os\n",
    "phone = os.environ.get(\"QUANTOS_USER\")\n",
    "token = os.environ.get(\"QUANTOS_TOKEN\")\n",
    "\n",
    "data_config = {\n",
    "  \"timeout\": 1800,\n",
    "  \"remote.data.address\": \"tcp://data.quantos.org:8910\",\n",
    "  \"remote.data.username\":  phone,\n",
    "  \"remote.data.password\":  token}\n",
    "\n",
    "dataview_folder = 'technical_analysis'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "### 1.2 初始化DataView"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Begin: DataApi login 18612562791@tcp://data.quantos.org:8910\n",
      "    login success \n",
      "\n",
      "Initialize config success.\n",
      "Query data...\n",
      "Query data - query...\n",
      "NOTE: price adjust method is [post adjust]\n",
      "201\n",
      "403\n",
      "605\n",
      "807\n",
      "1009\n",
      "1211\n",
      "201\n",
      "403\n",
      "605\n",
      "807\n",
      "1009\n",
      "1211\n",
      "Query data - daily fields prepared.\n",
      "Query instrument info...\n",
      "Query adj_factor...\n",
      "Query benchmark...\n",
      "Query benchmar member info...\n",
      "Data has been successfully prepared.\n",
      "\n",
      "Store data...\n",
      "Dataview has been successfully saved to:\n",
      "C:\\Users\\jfang\\AppData\\Roaming\\QuantosFinanceTerminal\\workspace\\__lectures\\__primaryschool\\technical_analysis\n",
      "\n",
      "You can load it with load_dataview('C:\\Users\\jfang\\AppData\\Roaming\\QuantosFinanceTerminal\\workspace\\__lectures\\__primaryschool\\technical_analysis')\n"
     ]
    }
   ],
   "source": [
    "# 选股范围和基准设为沪深300指数\n",
    "ds = RemoteDataService()\n",
    "ds.init_from_config(data_config)\n",
    "dv = DataView()\n",
    "\n",
    "props = {'start_date': 20130101, 'end_date': 20171031, 'universe': '000300.SH',\n",
    "         'fields': 'volume,turnover',\n",
    "         'freq': 1}\n",
    "\n",
    "dv.init_from_config(props, ds)\n",
    "dv.prepare_data()\n",
    "\n",
    "dv.save_dataview(dataview_folder)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "### 1.3 检查股票是否出现停牌、调处成份股和达到涨跌幅限制的情况，分析时将会过滤掉"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\QuantosTerminal\\python\\lib\\site-packages\\jaqs\\data\\py_expression_eval.py:472: RuntimeWarning: invalid value encountered in greater\n",
      "  res = arr > brr\n"
     ]
    }
   ],
   "source": [
    "# 判断个股当前是否达到涨跌停限制：达到 = True， 未达到 = False\n",
    "dv.add_formula('mask_limit_reached', 'Abs((open - Delay(close, 1)) / Delay(close, 1)) > 0.095', is_quarterly=False)\n",
    "\n",
    "# 判断个股当期是否为成份股：是成份股 = True， 非成份股 = False\n",
    "dv.add_formula('mask_index_member', '(index_member == 0)', is_quarterly=False)\n",
    "\n",
    "# 判断个股当前是否处于停牌状态\n",
    "trade_status = dv.get_ts('trade_status')\n",
    "mask_sus = trade_status == u'停牌'\n",
    "dv.append_df(mask_sus, 'mask_sus', is_quarterly=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将以上三个条件整合\n",
    "mask_limit_reached = dv.get_ts('mask_limit_reached')\n",
    "mask_index_member = dv.get_ts('mask_index_member')\n",
    "mask_sus = dv.get_ts('mask_sus')\n",
    "mask_all = np.logical_or(mask_sus, np.logical_or(mask_index_member, mask_limit_reached))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 取出股价序列和指数价格序列 用于计算超额收益\n",
    "这里使用后复权价格"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "price = dv.get_ts('close_adj')\n",
    "price_bench = dv.data_benchmark"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. 技术指标一：金叉死叉 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.1 定义金叉死叉，并通过add_formula添加到dataview中"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\QuantosTerminal\\python\\lib\\site-packages\\jaqs\\data\\py_expression_eval.py:608: FutureWarning: pd.rolling_mean is deprecated for DataFrame and will be removed in a future version, replace with \n",
      "\tDataFrame.rolling(window=5,center=False).mean()\n",
      "  return pd.rolling_mean(x, n)\n",
      "D:\\QuantosTerminal\\python\\lib\\site-packages\\jaqs\\data\\py_expression_eval.py:608: FutureWarning: pd.rolling_mean is deprecated for DataFrame and will be removed in a future version, replace with \n",
      "\tDataFrame.rolling(window=15,center=False).mean()\n",
      "  return pd.rolling_mean(x, n)\n",
      "D:\\QuantosTerminal\\python\\lib\\site-packages\\jaqs\\data\\py_expression_eval.py:481: RuntimeWarning: invalid value encountered in less\n",
      "  res = arr < brr\n",
      "D:\\QuantosTerminal\\python\\lib\\site-packages\\jaqs\\data\\py_expression_eval.py:472: RuntimeWarning: invalid value encountered in greater\n",
      "  res = arr > brr\n"
     ]
    }
   ],
   "source": [
    "# 定义快速均线(5天)和慢速均线(15天)\n",
    "dv.add_formula('fast_MA', 'Ts_Mean(close_adj, 5)', is_quarterly=False)\n",
    "dv.add_formula('slow_MA', 'Ts_Mean(close_adj, 15)', is_quarterly=False)\n",
    "\n",
    "# 定义金叉\n",
    "factor_formula = '(Delay(fast_MA, 1) < Delay(slow_MA, 1) ) && (fast_MA > slow_MA)'\n",
    "dv.add_formula('golden_cross', factor_formula, is_quarterly=False)\n",
    "\n",
    "# 定义死叉\n",
    "factor_formula = '(Delay(fast_MA, 1) > Delay(slow_MA, 1) ) && (fast_MA < slow_MA)'\n",
    "dv.add_formula('dark_cross', factor_formula, is_quarterly=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2 分析死叉信号"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Nan Data Count (should be zero) : 0;  Percentage of effective data: 94%\n",
      "Nan Data Count (should be zero) : 0;  Percentage of effective data: 94%\n",
      "Nan Data Count (should be zero) : 0;  Percentage of effective data: 94%\n",
      "Nan Data Count (should be zero) : 0;  Percentage of effective data: 93%\n"
     ]
    }
   ],
   "source": [
    "signal = dv.get_ts('dark_cross').shift(1, axis=0)  # avoid look-ahead bias\n",
    "obj = SignalDigger(output_folder='technical_analysis', output_format='plot')\n",
    "df_all, df_events, df_stats = obj.create_binary_event_report(signal, price, mask_all, price_bench,\n",
    "                                                             periods=[1, 5, 10, 20], group_by='year')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df_stats"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 以等权收益作为基准，计算超额收益\n",
    "sns.barplot(x='Period', y=0, hue='trade_date',\n",
    "            data=(df_stats['Annu. Ret.'] - df_stats['Annu. Ret. (all samp)']).reset_index())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.3 分析金叉信号"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "signal = dv.get_ts('golden_cross')  # avoid look-ahead bias\n",
    "obj = SignalDigger(output_folder=dataview_folder, output_format='plot')\n",
    "df_all, df_events, df_stats = obj.create_binary_event_report(signal, price, mask_all, price_bench,\n",
    "                                                             periods=[1, 5, 10, 20], group_by='year')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "df_stats"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 以等权收益作为基准，计算超额收益\n",
    "sns.barplot(x='Period', y=0, hue='trade_date',\n",
    "            data=(df_stats['Annu. Ret.'] - df_stats['Annu. Ret. (all samp)']).reset_index())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. 技术指标二：三根阳线改变预期"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.1 定义三根阳线，并通过add_formula加入dataview中"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义单根阳线\n",
    "formula = '(close_adj > open_adj) && ( ( (close_adj - open_adj)/(high_adj - low_adj) ) >= 0.7)'\n",
    "dv.add_formula('UP', formula, is_quarterly = False)\n",
    "# 定义三根阳线\n",
    "formula = 'UP && Delay(UP, 1) && Delay(UP, 2)'\n",
    "dv.add_formula('UP3', formula, is_quarterly = False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2 分析三根阳线信号"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "signal = dv.get_ts('UP3')  # avoid look-ahead bias\n",
    "price = dv.get_ts('close_adj')\n",
    "obj = SignalDigger(output_folder=dataview_folder, output_format='plot')\n",
    "df_all, df_events, df_stats = obj.create_binary_event_report(signal, price, mask_all, price_bench,\n",
    "                                                             periods=[1, 5, 10, 20], group_by='year')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "df_stats"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 以等权收益作为基准，计算超额收益\n",
    "sns.barplot(x='Period', y=0, hue='trade_date',\n",
    "            data=(df_stats['Annu. Ret.'] - df_stats['Annu. Ret. (all samp)']).reset_index())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. 技术指标三：跳空高开 / 低开"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.1 定义为今开减昨收，并通过add_formula加入dataview中"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义跳空高开\n",
    "formula = 'open_adj / Delay(close_adj, 1)'\n",
    "dv.add_formula('open_jump', formula, is_quarterly=False) # good"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.2 分析跳空高开信号 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "signal = dv.get_ts('open_jump')  # avoid look-ahead bias\n",
    "my_period = 5  # 5日调仓，一年10% cost，因而10%一下收益无法战胜成本\n",
    "\n",
    "obj = SignalDigger(output_folder=dataview_folder, output_format='plot')\n",
    "obj.process_signal_before_analysis(signal, price=price,\n",
    "                                   mask=mask_all,\n",
    "                                   n_quantiles=5, period=my_period,\n",
    "                                   benchmark_price=price_bench,\n",
    "                                   )\n",
    "res = obj.create_full_report()\n",
    "\n",
    "#没有纯空头收益，因为信号总是正的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
